namespace com.stifel.ProjectMgmt.Features.ProjectMgmt_Feature
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Reflection;
    using System.Runtime.InteropServices;
    using System.Xml;

    using com.stifel.Extensions.AssemblyExtensions;
    using com.stifel.Extensions.SharePointExtensions;
    using com.stifel.ProjectMgmtDao;
    using com.stifel.SharePoint;

    using Microsoft.SharePoint;
    using Microsoft.SharePoint.Administration;
    using Microsoft.SharePoint.Linq;

    /// <summary>
    /// This class handles events raised during feature activation, deactivation, installation, uninstallation, and upgrade.
    /// </summary>
    /// <remarks>
    /// The GUID attached to this class may be used during packaging and should not be modified.
    /// </remarks>
    [Guid( "6575578e-bd77-4f8c-b7a3-fd862522768a" )]
    public class ProjectMgmt_FeatureEventReceiver : SPFeatureReceiver
    {
        #region Fields

        public const string FEATURE = "com.stifel.ProjectMgmt";
        public const string FeatureId = "2c17e7d4-39ae-4f47-8e0c-3ac93d848892"; // SEE: ProjectMgmt_Feature.feature manifest.xml featureId
        public const string FEATURE_NAME = "Stifel Project Management - Site Collection";

        const string CONTENTTYPEGROUP = "Stifel";

        #endregion Fields

        #region Methods

        public override void FeatureActivated( SPFeatureReceiverProperties properties )
        {
            try
            {
                if ( !( properties.Feature.Parent is SPSite ) )
                {
                    CustomLoggingService.LogCritical( CustomLoggingService.Area.FeatureInfrastructure, "{0} :: Error activating feature. Feature parent is not of type SPSite.", FEATURE );
                    return;
                }

                CustomLoggingService.LogMessage( CustomLoggingService.Area.FeatureInfrastructure, "{0} :: Feature activating.", FEATURE );
                addFields( properties );
                createContentTypes( properties );
                CustomLoggingService.LogMessage( CustomLoggingService.Area.FeatureInfrastructure, "{0} :: Feature activated.", FEATURE );
            }
            catch ( Exception e )
            {
                throw new Exception( string.Format( "Error occurred in {0} FeatureActivated. {1} {2}", FEATURE, e.Message, e.StackTrace ), e );
            }
        }

        public override void FeatureDeactivating( SPFeatureReceiverProperties properties )
        {
            try
            {
                if ( !( properties.Feature.Parent is SPSite ) )
                {
                    CustomLoggingService.LogCritical( CustomLoggingService.Area.FeatureInfrastructure, "{0} :: Error deactivating feature. Feature parent is not of type SPSite.", FEATURE );
                    return;
                }

                CustomLoggingService.LogMessage( CustomLoggingService.Area.FeatureInfrastructure, "{0} :: Feature deactivating.", FEATURE );
                removeWebParts( properties );
                deleteContentTypes( properties );
                removeFields( properties );
                CustomLoggingService.LogMessage( CustomLoggingService.Area.FeatureInfrastructure, "{0} :: Feature deactivated." );
            }
            catch ( Exception e )
            {
                throw new Exception( string.Format( "Error occurred in {0} FeatureDeactivating. {1} {2}", FEATURE, e.Message, e.StackTrace ), e );
            }
        }

        public override void FeatureInstalled( SPFeatureReceiverProperties properties )
        {
            try
            {
                CustomLoggingService.LogMessage( CustomLoggingService.Area.FeatureInfrastructure, "{0} :: Feature installed.", FEATURE );
            }
            catch ( Exception e )
            {
                throw new Exception( string.Format( "Error occurred in {0} FeatureInstalled function. {1} {2}", FEATURE, e.Message, e.StackTrace ), e );
            }
        }

        public override void FeatureUninstalling( SPFeatureReceiverProperties properties )
        {
            try
            {
                CustomLoggingService.LogMessage( CustomLoggingService.Area.FeatureInfrastructure, "{0} :: Feature uninstalling.", FEATURE );
            }
            catch ( Exception e )
            {
                throw new Exception( string.Format( "Error occurred in {0} FeatureUninstalling. {1} {2}", FEATURE, e.Message, e.StackTrace ), e );
            }
        }

        void addFields( SPFeatureReceiverProperties properties )
        {
            XmlNodeList fields = getFieldDefinitionsAsXml( properties );
            if ( fields != null )
            {
                using ( SPWeb spWeb = properties.GetWeb( ) )
                {
                    foreach ( XmlNode field in fields )
                    {
                        XmlAttribute a = field.Attributes[ "Name" ];
                        if ( a != null )
                        {
                            string name = a.Value;
                            if ( !spWeb.Fields.ContainsFieldWithStaticName( name ) )
                                spWeb.Fields.AddFieldAsXml( field.OuterXml );
                        }
                    }
                }
            }
        }

        void createContentTypes( SPFeatureReceiverProperties properties )
        {
            StifelProject_createContentType( properties );
            StifelTask_createContentType( properties );
        }

        void deleteContentTypes( SPFeatureReceiverProperties properties )
        {
            StifelProject_deleteContentType( properties );
            StifelTask_deleteContentType( properties );
        }

        string getContentTypeId<T>( )
        {
            MemberInfo info = typeof( T );
            object[ ] o = info.GetCustomAttributes( typeof( ContentTypeAttribute ), false );
            if ( o.Length > 0 )
                return ( ( ContentTypeAttribute ) o[ 0 ] ).Id;
            else
                return string.Empty;
        }

        XmlNodeList getFieldDefinitionsAsXml( SPFeatureReceiverProperties properties )
        {
            XmlNodeList fields = null;
            string s = Assembly.GetExecutingAssembly( ).GetFullyQualifiedManifestResourceName( "projects.fields.xml" );
            string xml = Assembly.GetExecutingAssembly( ).GetManifestResourceAsString( s );
            if ( !string.IsNullOrEmpty( xml ) )
            {
                XmlDocument d = new XmlDocument( );
                d.LoadXml( xml );
                XmlNode n = d.SelectSingleNode( "Fields" );
                fields = n.SelectNodes( "Field" );
            }
            return fields;
        }

        void removeFields( SPFeatureReceiverProperties properties )
        {
            XmlNodeList fields = getFieldDefinitionsAsXml( properties );
            if ( fields != null )
            {
                using ( SPWeb spWeb = properties.GetWeb( ) )
                {
                    foreach ( XmlNode field in fields )
                    {
                        XmlAttribute a = field.Attributes[ "Name" ];
                        if ( a != null )
                        {
                            string name = a.Value;
                            if ( spWeb.Fields.ContainsFieldWithStaticName( name ) )
                            {
                                SPField f = spWeb.Fields.GetFieldByInternalName( name );
                                if ( !f.UsedInWebContentTypes )
                                    spWeb.Fields.Delete( name );
                            }
                        }
                    }
                }
            }
        }

        void removeWebParts( SPFeatureReceiverProperties properties )
        {
            using ( SPWeb spWeb = properties.GetWeb( ) )
            {
                List<string> l = new List<string>( );
                SPElementDefinitionCollection elementCollection = properties.Definition.GetElementDefinitions( System.Globalization.CultureInfo.CurrentCulture );
                foreach ( SPElementDefinition element in elementCollection )
                {
                    foreach ( XmlElement xmlNode in element.XmlDefinition.ChildNodes )
                    {
                        if ( xmlNode != null && xmlNode.Name.Equals( "File" ) )
                        {
                            l.Add( xmlNode.Attributes[ "Url" ].Value );
                        }
                    }
                }

                // Get the Web Part Catalog
                SPList wpGallery = spWeb.GetCatalog( SPListTemplateType.WebPartCatalog );

                // Find the list items that matchs the Feature Web Parts
                List<SPListItem> items = new List<SPListItem>( );
                if ( wpGallery != null )
                {
                    foreach ( SPListItem item in wpGallery.Items )
                    {
                        if ( item != null && item.File != null && l.Contains( item.File.Name ) )
                        {
                            items.Add( item );
                        }
                    }
                }

                // Remove the Feature Web Parts from the Web Part catalog
                foreach ( SPListItem item in items )
                {
                    item.Delete( );
                }
                spWeb.Update( );
            }
        }

        void StifelProject_createContentType( SPFeatureReceiverProperties properties )
        {
            string contentTypeName = "Stifel Project";
            List<string> f = new string[ ] {
                "sn_prjmgt_ProjectDescription",
                "sn_prjmgt_ProjectStatus",
                "sn_prjmgt_DueDate",
                "sn_prjmgt_StartDate",
                "sn_prjmgt_CompletedDate",
                "sn_prjmgt_TeamLead",
                "sn_prjmgt_TeamRanking",
                "sn_prjmgt_OverallRanking"
            }.ToList( );
            List<string> hidden = new string[ ] {
                "sn_prjmgt_OverallRanking"
            }.ToList( );
            List<string> required = new string[ ] {
                "sn_prjmgt_DueDate"
            }.ToList( );
            using ( SPWeb spWeb = properties.GetWeb( ) )
            {
                if ( !spWeb.ContainsContentType( contentTypeName ) )
                {
                    List<SPField> fields = new List<SPField>( );
                    foreach ( string s in f )
                    {
                        SPField field = spWeb.Fields.GetFieldByInternalName( s );
                        if ( field != null )
                        {
                            if ( hidden.Contains( s ) )
                                field.Hidden = true;
                            if ( required.Contains( s ) )
                                field.Required = true;
                            fields.Add( field );
                        }
                    }
                    spWeb.CreateContentType( getContentTypeId<StifelProject>( ), CONTENTTYPEGROUP, contentTypeName, "Create a new Stifel project folder.", false, fields.ToArray( ) );
                }
            }
        }

        void StifelProject_deleteContentType( SPFeatureReceiverProperties properties )
        {
            string contentTypeName = "Stifel Project";

            using ( SPWeb spWeb = properties.GetWeb( ) )
            {
                spWeb.DeleteContentType( contentTypeName );
            }
        }

        void StifelTask_createContentType( SPFeatureReceiverProperties properties )
        {
            string contentTypeName = "Stifel Task";
            List<string> f = new string[ ] {
                "sn_prjmgt_TaskDescription",
                "sn_prjmgt_TaskStatus",
                "sn_prjmgt_TaskPriority",
                "sn_prjmgt_PercentTaskComplete",
                "sn_prjmgt_DueDate",
                "sn_prjmgt_StartDate",
                "sn_prjmgt_CompletedDate",
                "sn_prjmgt_TaskAssignedTo"
            }.ToList( );
            using ( SPWeb spWeb = properties.GetWeb( ) )
            {
                if ( !spWeb.ContainsContentType( contentTypeName ) )
                {
                    List<SPField> fields = new List<SPField>( );
                    foreach ( string s in f )
                    {
                        SPField field = spWeb.Fields.GetFieldByInternalName( s );
                        if ( field != null )
                            fields.Add( field );
                    }
                    spWeb.CreateContentType( getContentTypeId<StifelTask>( ), CONTENTTYPEGROUP, contentTypeName, "Create a new Stifel project task.", false, fields.ToArray( ) );
                }
            }
        }

        void StifelTask_deleteContentType( SPFeatureReceiverProperties properties )
        {
            string contentTypeName = "Stifel Task";
            using ( SPWeb spWeb = properties.GetWeb( ) )
            {
                spWeb.DeleteContentType( contentTypeName );
            }
        }

        #endregion Methods

        #region Other

        // Uncomment the method below to handle the event raised when a feature is upgrading.
        //public override void FeatureUpgrading(SPFeatureReceiverProperties properties, string upgradeActionName, System.Collections.Generic.IDictionary<string, string> parameters)
        //{
        //}

        #endregion Other
    }
}